/**
  SUNNY project, Anyang Normal University, IMP-CAS
  \class TATreeCol
  \brief storing vector elements in a TTree object for large vectors
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021/02/10
  \date Last modified: 2022/11/19 by SUN Yazhou
  \copyright 2020-2021 SUN Yazhou
  \copyright SUNNY project, Anyang Normal University, IMP-CAS
*/

#include "config.h" // contains user switch of definition of ROOT and OpenCV
#include "TATreeCol.h"
#include "TAException.h"

#ifdef _ROOT_
#include "TTree.h"
#include "TFile.h"
#endif

TFile *TATreeCol::kCurrentFile = nullptr;
int TATreeCol::kObjCount = 0;

TATreeCol::TATreeCol(const string &name, const string &title) : fTree(nullptr){
#ifdef _ROOT_
  if(!kCurrentFile) kCurrentFile = new TFile("fci.root", "RECREATE");
  char name1[512];
  sprintf(name1, "%s_%d", name.c_str(), kObjCount++);
  fTree = new TTree(name1, title.c_str());
#else
  TAException::Error("TATreeCol", "CreateBranch: ROOT not found.");
#endif
} // end constructor

// NOTE that user has to set branch addresses to their own member data manually
TATreeCol::TATreeCol(const TATreeCol &t){
  fTree = nullptr; // to avoid erroneous delete in operator=
  *this = t;
} // end the copy ctor

// the move ctor
TATreeCol::TATreeCol(TATreeCol &&t){
  fTree = t.fTree;
  t.fTree = nullptr; // to avoid erroneous delete in dtor
} // end the move ctor

TATreeCol &TATreeCol::operator=(const TATreeCol &t){
#ifdef _ROOT_
  if(fTree){ delete fTree; fTree = nullptr; }
  char name[512];
  sprintf(name, "%s_%d", t.fTree->GetName(), kObjCount++);
  fTree = new TTree(name, t.fTree->GetTitle());
#else
  TAException::Error("TATreeCol", "CreateBranch: ROOT not found.");
#endif
  return *this;
} // end member function operator=

TATreeCol::~TATreeCol(){
#ifdef _ROOT_
  if(fTree){ delete fTree; fTree = nullptr; }
#else
  TAException::Error("TATreeCol", "dctor: ROOT not found.");
#endif
} // end destructor

// delete all entries //
void TATreeCol::Clear(){
#ifdef _ROOT_
  if(!GetEntries()) return;

  TTree *t = fTree;
  fTree = new TTree(t->GetName(), t->GetTitle());
  t->Delete("all"); t = nullptr;

  CreateBranch();
#else
  TAException::Error("TATreeCol", "Clear: ROOT not found.");
#endif
} // end member fucntion Clear

void TATreeCol::Save(){
#ifdef _ROOT_
  fTree->Write("", TObject::kOverwrite);
#else
  TAException::Error("TATreeCol", "Save: ROOT not found.");
#endif
} // end member function Save

void TATreeCol::CloseFile(){
#ifdef _ROOT_
  if(!kCurrentFile){
    TAException::Warn("TATreeCol", "CloseFile: Called once already.");
    return;
  } // end if
  kCurrentFile->Close();
  delete kCurrentFile; kCurrentFile = nullptr;
#else
    TAException::Error("TATreeCol", "CloseFile: ROOT not found.");
#endif
} // end member function CloseFile

ull TATreeCol::GetEntries() const{
#ifdef _ROOT_
  return fTree->GetEntries();
#else
  TAException::Error("TATreeCol", "GetEntry: ROOT not found.");
  return 0;
#endif
} // end member function GetEntries

// TTree::GetEntry with branch address checking
void TATreeCol::GetEntry(ull i) const{
#ifdef _ROOT_
  if(i >= GetEntries()) TAException::Error("TATreeCol",
    "GetEntry: required entry index out of range");
  fTree->GetEntry(i);
#else
  TAException::Error("TATreeCol", "GetEntry: ROOT not found.");
#endif
} // end member function GetEntry

void TATreeCol::Fill() const{
#ifdef _ROOT_
  fTree->Fill();
#else
  TAException::Error("TATreeCol", "Fill: ROOT not found.");
#endif
} // end member function Fill
